import { BaseService } from '../framework/base-service.js'
import _ from 'lodash'

export default class ProxyService extends BaseService {
  static metadata = {
    name: 'proxy',
    dependencies: [],
    singleton: true
  }
  
  constructor() {
    super()
    this.cache = new Map()
    this.cacheExpiry = 3600000 // 1小时缓存
  }
  
  async onInit() {
    // 加载代理配置
    this.proxyConfig = this.config.get('proxy', {})
    this.wrapiConfig = this.proxyConfig.wrapi || {}
    this.rules = this.proxyConfig.rules || {}
    
    // 初始化AK池（用于负载均衡）
    this.akPools = {
      bmap: this.parseAks(this.wrapiConfig.bmap?.aks),
      amap: this.parseAks(this.wrapiConfig.amap?.aks)
    }
    
    this.akIndex = {
      bmap: 0,
      amap: 0
    }
    
    this.logger.info('ProxyService', '✅ Proxy service initialized')
  }
  
  registerRoutes(app) {
    // 百度地图API代理
    app.get('/_/bmap/*', async c => {
      const path = c.req.path.replace('/_/bmap/', '')
      return await this.proxyBmap(path, c.req.query())
    })
    
    app.post('/_/bmap/*', async c => {
      const path = c.req.path.replace('/_/bmap/', '')
      const body = await c.req.json()
      return await this.proxyBmap(path, body)
    })
    
    // 高德地图API代理
    app.get('/_/amap/*', async c => {
      const path = c.req.path.replace('/_/amap/', '')
      return await this.proxyAmap(path, c.req.query())
    })
    
    app.post('/_/amap/*', async c => {
      const path = c.req.path.replace('/_/amap/', '')
      const body = await c.req.json()
      return await this.proxyAmap(path, body)
    })
    
    // GIS转换服务
    app.get('/gis/convert', async c => {
      const { from = 'gps', to = 'bmap', xys } = c.req.query()
      
      try {
        const result = await this.convertCoordinate(from, to, xys)
        return c.json({ status: 0, result })
      } catch (err) {
        return c.json({ status: 1, error: err.message })
      }
    })
    
    // 路径规划服务
    app.get('/gis/driving', async c => {
      const { origin, destination, tactics = 'regular' } = c.req.query()
      
      try {
        const mapType = this.config.get('biz.map.using', 'bmap')
        const result = await this.driving(mapType, origin, destination, tactics)
        return c.json({ status: 0, result })
      } catch (err) {
        return c.json({ status: 1, error: err.message })
      }
    })
    
    // 地点搜索建议
    app.get('/gis/suggestion', async c => {
      const { query, region, city_limit = 'true' } = c.req.query()
      
      try {
        const mapType = this.config.get('biz.map.using', 'bmap')
        const result = await this.suggestion(mapType, query, region, city_limit)
        return c.json({ status: 0, result })
      } catch (err) {
        return c.json({ status: 1, error: err.message })
      }
    })
    
    // 路径矩阵计算
    app.post('/gis/routematrix', async c => {
      const { origins, destinations } = await c.req.json()
      
      try {
        const mapType = this.config.get('biz.map.using', 'bmap')
        const result = await this.routeMatrix(mapType, origins, destinations)
        return c.json({ status: 0, result })
      } catch (err) {
        return c.json({ status: 1, error: err.message })
      }
    })
    
    return true
  }
  
  // 百度地图代理
  async proxyBmap(path, params) {
    const rules = this.rules.bmap || {}
    const exchange = rules.exchange || {}
    
    // 查找对应的目标URL
    let targetUrl = null
    for (const [prefix, target] of Object.entries(exchange)) {
      if (path.startsWith(prefix.replace('/_/bmap/', ''))) {
        targetUrl = `${target}/${path}`
        break
      }
    }
    
    if (!targetUrl) {
      targetUrl = `http://api.map.baidu.com/${path}`
    }
    
    // 添加AK参数
    if (!params.ak) {
      params.ak = this.getNextAk('bmap')
    }
    
    // 检查缓存
    const cacheKey = `bmap:${targetUrl}:${JSON.stringify(params)}`
    const cached = this.getCache(cacheKey)
    if (cached) {
      return cached
    }
    
    try {
      // 构建请求URL
      const url = new URL(targetUrl)
      Object.entries(params).forEach(([key, value]) => {
        url.searchParams.append(key, value)
      })
      
      // 发送请求
      const response = await fetch(url.toString())
      const contentType = response.headers.get('content-type')
      
      let result
      if (contentType?.includes('json')) {
        result = await response.json()
      } else if (contentType?.includes('image')) {
        result = await response.arrayBuffer()
      } else {
        result = await response.text()
      }
      
      // 缓存结果
      this.setCache(cacheKey, result)
      
      return result
    } catch (err) {
      this.logger.error('ProxyService', 'Bmap proxy failed:', { error: err.message, path, params })
      throw err
    }
  }
  
  // 高德地图代理
  async proxyAmap(path, params) {
    const rules = this.rules.amap || {}
    const exchange = rules.exchange || {}
    
    // 查找对应的目标URL
    let targetUrl = null
    for (const [prefix, target] of Object.entries(exchange)) {
      if (path.startsWith(prefix.replace('/_/amap/', ''))) {
        targetUrl = `${target}/${path}`
        break
      }
    }
    
    if (!targetUrl) {
      targetUrl = `https://restapi.amap.com/${path}`
    }
    
    // 添加key参数
    if (!params.key) {
      params.key = this.getNextAk('amap')
    }
    
    // 检查缓存
    const cacheKey = `amap:${targetUrl}:${JSON.stringify(params)}`
    const cached = this.getCache(cacheKey)
    if (cached) {
      return cached
    }
    
    try {
      // 构建请求URL
      const url = new URL(targetUrl)
      Object.entries(params).forEach(([key, value]) => {
        url.searchParams.append(key, value)
      })
      
      // 发送请求
      const response = await fetch(url.toString())
      const contentType = response.headers.get('content-type')
      
      let result
      if (contentType?.includes('json')) {
        result = await response.json()
      } else if (contentType?.includes('image')) {
        result = await response.arrayBuffer()
      } else {
        result = await response.text()
      }
      
      // 缓存结果
      this.setCache(cacheKey, result)
      
      return result
    } catch (err) {
      this.logger.error('ProxyService', 'Amap proxy failed:', { error: err.message, path, params })
      throw err
    }
  }
  
  // 坐标转换
  async convertCoordinate(from, to, xys) {
    const convertConfig = this.wrapiConfig.bmap?.convert || {}
    const models = convertConfig.models || {}
    
    const key = `${from}_${to}`
    const model = models[key]
    
    if (!model) {
      throw new Error(`不支持的坐标转换: ${from} -> ${to}`)
    }
    
    // 处理组合转换（如 gps_amap = gps_bmap|bmap_amap）
    if (model.includes('|')) {
      const steps = model.split('|')
      let result = xys
      
      for (const step of steps) {
        const [stepFrom, stepTo] = step.split('_')
        result = await this.convertCoordinate(stepFrom, stepTo, result)
      }
      
      return result
    }
    
    // 单步转换
    const api = convertConfig.api || 'https://api.map.baidu.com/geoconv/v2/'
    const ak = this.getNextAk('bmap')
    
    const url = new URL(api)
    url.searchParams.append('coords', xys)
    url.searchParams.append('from', this.getCoordType(from))
    url.searchParams.append('to', this.getCoordType(to))
    url.searchParams.append('ak', ak)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== 0) {
        throw new Error(data.message || '坐标转换失败')
      }
      
      return data.result
    } catch (err) {
      this.logger.error('ProxyService', 'Coordinate conversion failed:', { error: err.message })
      throw err
    }
  }
  
  // 路径规划
  async driving(mapType, origin, destination, tactics) {
    if (mapType === 'bmap') {
      return await this.drivingBmap(origin, destination, tactics)
    } else {
      return await this.drivingAmap(origin, destination, tactics)
    }
  }
  
  async drivingBmap(origin, destination, tactics) {
    const drivingConfig = this.wrapiConfig.bmap?.driving || {}
    const api = drivingConfig.api || 'https://api.map.baidu.com/direction/v2/driving'
    const ak = this.getNextAk('bmap')
    
    const tacticsMap = drivingConfig.model || {
      'regular': 0,    // 常规路线
      'avoid': 1,      // 躲避拥堵
      'shortest': 2,   // 最短路径
      'notoll': 3,     // 不走高速
      'distance': 4    // 最短距离
    }
    
    const url = new URL(api)
    url.searchParams.append('origin', origin)
    url.searchParams.append('destination', destination)
    url.searchParams.append('tactics', tacticsMap[tactics] || 0)
    url.searchParams.append('output', 'json')
    url.searchParams.append('ak', ak)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== 0) {
        throw new Error(data.message || '路径规划失败')
      }
      
      return data.result
    } catch (err) {
      this.logger.error('ProxyService', 'Bmap driving failed:', { error: err.message })
      throw err
    }
  }
  
  async drivingAmap(origin, destination, tactics) {
    const api = 'https://restapi.amap.com/v3/direction/driving'
    const key = this.getNextAk('amap')
    
    const tacticsMap = {
      'regular': 0,    // 常规路线
      'avoid': 1,      // 躲避拥堵
      'shortest': 2,   // 最短路径
      'notoll': 3,     // 不走高速
      'distance': 4    // 最短距离
    }
    
    const url = new URL(api)
    url.searchParams.append('origin', origin)
    url.searchParams.append('destination', destination)
    url.searchParams.append('strategy', tacticsMap[tactics] || 0)
    url.searchParams.append('extensions', 'all')
    url.searchParams.append('output', 'json')
    url.searchParams.append('key', key)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== '1') {
        throw new Error(data.info || '路径规划失败')
      }
      
      return data.route
    } catch (err) {
      this.logger.error('ProxyService', 'Amap driving failed:', { error: err.message })
      throw err
    }
  }
  
  // 地点搜索建议
  async suggestion(mapType, query, region, cityLimit) {
    if (mapType === 'bmap') {
      return await this.suggestionBmap(query, region, cityLimit)
    } else {
      return await this.suggestionAmap(query, region, cityLimit)
    }
  }
  
  async suggestionBmap(query, region, cityLimit) {
    const api = 'https://api.map.baidu.com/place/v2/suggestion'
    const ak = this.getNextAk('bmap')
    
    const url = new URL(api)
    url.searchParams.append('query', query)
    url.searchParams.append('region', region)
    url.searchParams.append('city_limit', cityLimit === 'true' ? 'true' : 'false')
    url.searchParams.append('output', 'json')
    url.searchParams.append('ak', ak)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== 0) {
        throw new Error(data.message || '搜索建议失败')
      }
      
      return data.result
    } catch (err) {
      this.logger.error('ProxyService', 'Bmap suggestion failed:', { error: err.message })
      throw err
    }
  }
  
  async suggestionAmap(query, region, cityLimit) {
    const api = 'https://restapi.amap.com/v3/assistant/inputtips'
    const key = this.getNextAk('amap')
    
    const url = new URL(api)
    url.searchParams.append('keywords', query)
    url.searchParams.append('city', region)
    url.searchParams.append('citylimit', cityLimit === 'true' ? 'true' : 'false')
    url.searchParams.append('output', 'json')
    url.searchParams.append('key', key)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== '1') {
        throw new Error(data.info || '搜索建议失败')
      }
      
      return data.tips
    } catch (err) {
      this.logger.error('ProxyService', 'Amap suggestion failed:', { error: err.message })
      throw err
    }
  }
  
  // 路径矩阵计算
  async routeMatrix(mapType, origins, destinations) {
    if (mapType === 'bmap') {
      return await this.routeMatrixBmap(origins, destinations)
    } else {
      return await this.routeMatrixAmap(origins, destinations)
    }
  }
  
  async routeMatrixBmap(origins, destinations) {
    const api = 'https://api.map.baidu.com/routematrix/v2/driving'
    const ak = this.getNextAk('bmap')
    
    const url = new URL(api)
    url.searchParams.append('origins', origins)
    url.searchParams.append('destinations', destinations)
    url.searchParams.append('output', 'json')
    url.searchParams.append('ak', ak)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== 0) {
        throw new Error(data.message || '路径矩阵计算失败')
      }
      
      return data.result
    } catch (err) {
      this.logger.error('ProxyService', 'Bmap route matrix failed:', { error: err.message })
      throw err
    }
  }
  
  async routeMatrixAmap(origins, destinations) {
    const api = 'https://restapi.amap.com/v3/distance'
    const key = this.getNextAk('amap')
    
    const url = new URL(api)
    url.searchParams.append('origins', origins)
    url.searchParams.append('destination', destinations)
    url.searchParams.append('type', '1') // 驾车
    url.searchParams.append('output', 'json')
    url.searchParams.append('key', key)
    
    try {
      const response = await fetch(url.toString())
      const data = await response.json()
      
      if (data.status !== '1') {
        throw new Error(data.info || '路径矩阵计算失败')
      }
      
      return data.results
    } catch (err) {
      this.logger.error('ProxyService', 'Amap route matrix failed:', { error: err.message })
      throw err
    }
  }
  
  // 辅助方法
  parseAks(akString) {
    if (!akString) return []
    return akString.split(',').map(ak => ak.trim()).filter(ak => ak)
  }
  
  getNextAk(mapType) {
    const pool = this.akPools[mapType]
    if (!pool || pool.length === 0) {
      throw new Error(`No API keys configured for ${mapType}`)
    }
    
    const ak = pool[this.akIndex[mapType]]
    this.akIndex[mapType] = (this.akIndex[mapType] + 1) % pool.length
    
    return ak
  }
  
  getCoordType(type) {
    const typeMap = {
      'gps': 1,     // WGS84坐标
      'gcj02': 3,   // 国测局坐标（火星坐标）
      'bmap': 5,    // 百度坐标
      'amap': 3     // 高德坐标（同国测局）
    }
    return typeMap[type] || 1
  }
  
  getCache(key) {
    const cached = this.cache.get(key)
    if (!cached) return null
    
    if (Date.now() - cached.time > this.cacheExpiry) {
      this.cache.delete(key)
      return null
    }
    
    return cached.data
  }
  
  setCache(key, data) {
    // 限制缓存大小
    if (this.cache.size > 1000) {
      const firstKey = this.cache.keys().next().value
      this.cache.delete(firstKey)
    }
    
    this.cache.set(key, {
      data,
      time: Date.now()
    })
  }
}